package com.sxjs.common.widget.autoscrollviewpager;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.DrawableRes;
import android.support.annotation.LayoutRes;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.sxjs.common.R;
import com.sxjs.common.widget.autoscrollviewpager.transformer.BGAPageTransformer;
import com.sxjs.common.widget.autoscrollviewpager.transformer.TransitionEffect;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

import static android.view.Gravity.BOTTOM;


public class BGABanner extends RelativeLayout implements BGAViewPager.AutoPlayDelegate, ViewPager.OnPageChangeListener {
	private static final int RMP = LayoutParams.MATCH_PARENT;
	private static final int RWC = LayoutParams.WRAP_CONTENT;
	private static final int LWC = LinearLayout.LayoutParams.WRAP_CONTENT;
	private static final int NO_PLACEHOLDER_DRAWABLE = -1;
	private static final int VEL_THRESHOLD = 400;
	private BGAViewPager mViewPager;
	private List<View> mHackyViews;
	private List<View> mViews;
	private List<String> mTips;
	private LinearLayout mPointRealContainerLl;
	private TextView mTipTv;
	private boolean mAutoPlayAble = true;
	private int mAutoPlayInterval = 3000;
	private int mPageChangeDuration = 800;
	private int mPointGravity = Gravity.CENTER_HORIZONTAL | BOTTOM;
	private int mPointLeftRightMargin;
	private int mPointTopBottomMargin;
	private int mPointContainerLeftRightPadding;
	private int mTipTextSize;
	private int mTipTextColor = Color.WHITE;
	private int mPointDrawableResId = R.drawable.bga_banner_selector_point_solid;
	private Drawable mPointContainerBackgroundDrawable;
	private AutoPlayTask mAutoPlayTask;
	private int mPageScrollPosition;
	private float mPageScrollPositionOffset;
	private TransitionEffect mTransitionEffect;
	private ImageView mPlaceholderIv;
	private ImageView.ScaleType mPlaceholderScaleType = ImageView.ScaleType.CENTER_CROP;
	private int mPlaceholderDrawableResId = NO_PLACEHOLDER_DRAWABLE;
	private List<? extends Object> mModels;
	private Delegate mDelegate;
	private Adapter mAdapter;
	private int mOverScrollMode = OVER_SCROLL_NEVER;
	private ViewPager.OnPageChangeListener mOnPageChangeListener;
	private boolean mIsNumberIndicator = false;
	private TextView mNumberIndicatorTv;
	private int mNumberIndicatorTextColor = Color.WHITE;
	private int mNumberIndicatorTextSize;
	private Drawable mNumberIndicatorBackground;
	private boolean mIsNeedShowIndicatorOnOnlyOnePage;
	private boolean mAllowUserScrollable = true;
	private View mSkipView;
	private View mEnterView;
	private GuideDelegate mGuideDelegate;
	private int mContentBottomMargin;
	private int mIndicatorBottomMargin;
	private boolean mIsFirstInvisible = true;
	private boolean bannerButtomShade = false;
	/**
	 * 纵横比测量
	 */
	private final BannerAspectRatioMeasure.Spec mMeasureSpec = new BannerAspectRatioMeasure.Spec();
	/**
	 * 宽高显示比例
	 */
	private float mAspectRatio = 0;

	private static final ImageView.ScaleType[] sScaleTypeArray = {
			ImageView.ScaleType.MATRIX,
			ImageView.ScaleType.FIT_XY,
			ImageView.ScaleType.FIT_START,
			ImageView.ScaleType.FIT_CENTER,
			ImageView.ScaleType.FIT_END,
			ImageView.ScaleType.CENTER,
			ImageView.ScaleType.CENTER_CROP,
			ImageView.ScaleType.CENTER_INSIDE
	};

	private BGAOnNoDoubleClickListener mGuideOnNoDoubleClickListener = new BGAOnNoDoubleClickListener() {
		@Override
		public void onNoDoubleClick(View v) {
			if (mGuideDelegate != null) {
				mGuideDelegate.onClickEnterOrSkip();
			}
		}
	};


	public BGABanner(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public BGABanner(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initDefaultAttrs(context);
		initCustomAttrs(context, attrs);
		initView(context);
	}

	private void initDefaultAttrs(Context context) {
		mAutoPlayTask = new AutoPlayTask(this);

		mPointLeftRightMargin = BGABannerUtil.dp2px(context, 3);
		mPointTopBottomMargin = BGABannerUtil.dp2px(context, 3);
		mPointContainerLeftRightPadding = BGABannerUtil.dp2px(context, 10);
		mTipTextSize = BGABannerUtil.sp2px(context, 10);
		mPointContainerBackgroundDrawable = new ColorDrawable(Color.parseColor("#44aaaaaa"));
		mTransitionEffect = TransitionEffect.Default;
		mNumberIndicatorTextSize = BGABannerUtil.sp2px(context, 10);

		mContentBottomMargin = 0;
		mIndicatorBottomMargin = 0;
	}

	private void initCustomAttrs(Context context, AttributeSet attrs) {
		TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BGABanner);
		final int N = typedArray.getIndexCount();
		for (int i = 0; i < N; i++) {
			initCustomAttr(typedArray.getIndex(i), typedArray);
		}
		typedArray.recycle();
	}

	private void initCustomAttr(int attr, TypedArray typedArray) {
		if (attr == R.styleable.BGABanner_banner_pointDrawable) {
			mPointDrawableResId = typedArray.getResourceId(attr, R.drawable.bga_banner_selector_point_solid);
		} else if (attr == R.styleable.BGABanner_banner_pointContainerBackground) {
			mPointContainerBackgroundDrawable = typedArray.getDrawable(attr);
		} else if (attr == R.styleable.BGABanner_banner_pointLeftRightMargin) {
			mPointLeftRightMargin = typedArray.getDimensionPixelSize(attr, mPointLeftRightMargin);
		} else if (attr == R.styleable.BGABanner_banner_pointContainerLeftRightPadding) {
			mPointContainerLeftRightPadding = typedArray.getDimensionPixelSize(attr, mPointContainerLeftRightPadding);
		} else if (attr == R.styleable.BGABanner_banner_pointTopBottomMargin) {
			mPointTopBottomMargin = typedArray.getDimensionPixelSize(attr, mPointTopBottomMargin);
		} else if (attr == R.styleable.BGABanner_banner_indicatorGravity) {
			mPointGravity = typedArray.getInt(attr, mPointGravity);
		} else if (attr == R.styleable.BGABanner_banner_pointAutoPlayAble) {
			mAutoPlayAble = typedArray.getBoolean(attr, mAutoPlayAble);
		} else if (attr == R.styleable.BGABanner_banner_pointAutoPlayInterval) {
			mAutoPlayInterval = typedArray.getInteger(attr, mAutoPlayInterval);
		} else if (attr == R.styleable.BGABanner_banner_pageChangeDuration) {
			mPageChangeDuration = typedArray.getInteger(attr, mPageChangeDuration);
		} else if (attr == R.styleable.BGABanner_banner_transitionEffect) {
			int ordinal = typedArray.getInt(attr, TransitionEffect.Accordion.ordinal());
			mTransitionEffect = TransitionEffect.values()[ordinal];
		} else if (attr == R.styleable.BGABanner_banner_tipTextColor) {
			mTipTextColor = typedArray.getColor(attr, mTipTextColor);
		} else if (attr == R.styleable.BGABanner_banner_tipTextSize) {
			mTipTextSize = typedArray.getDimensionPixelSize(attr, mTipTextSize);
		} else if (attr == R.styleable.BGABanner_banner_placeholderDrawable) {
			mPlaceholderDrawableResId = typedArray.getResourceId(attr, mPlaceholderDrawableResId);
		} else if (attr == R.styleable.BGABanner_banner_isNumberIndicator) {
			mIsNumberIndicator = typedArray.getBoolean(attr, mIsNumberIndicator);
		} else if (attr == R.styleable.BGABanner_banner_numberIndicatorTextColor) {
			mNumberIndicatorTextColor = typedArray.getColor(attr, mNumberIndicatorTextColor);
		} else if (attr == R.styleable.BGABanner_banner_numberIndicatorTextSize) {
			mNumberIndicatorTextSize = typedArray.getDimensionPixelSize(attr, mNumberIndicatorTextSize);
		} else if (attr == R.styleable.BGABanner_banner_numberIndicatorBackground) {
			mNumberIndicatorBackground = typedArray.getDrawable(attr);
		} else if (attr == R.styleable.BGABanner_banner_isNeedShowIndicatorOnOnlyOnePage) {
			mIsNeedShowIndicatorOnOnlyOnePage = typedArray.getBoolean(attr, mIsNeedShowIndicatorOnOnlyOnePage);
		} else if (attr == R.styleable.BGABanner_banner_contentBottomMargin) {
			mContentBottomMargin = typedArray.getDimensionPixelSize(attr, mContentBottomMargin);
		} else if (attr == R.styleable.BGABanner_banner_indicatorButtomMargin) {
			mIndicatorBottomMargin = typedArray.getDimensionPixelSize(attr, mIndicatorBottomMargin);
		} else if (attr == R.styleable.BGABanner_banner_buttomShade) {
			bannerButtomShade = typedArray.getBoolean(attr, bannerButtomShade);
		} else if (attr == R.styleable.BGABanner_android_scaleType) {
			final int index = typedArray.getInt(attr, -1);
			if (index >= 0 && index < sScaleTypeArray.length) {
				mPlaceholderScaleType = sScaleTypeArray[index];
			}
		} else if (attr == R.styleable.BGABanner_banner_viewAspectRatio) {
			mAspectRatio = typedArray.getFloat(attr, 0);
		}

	}

	/**
	 * Sets the desired aspect ratio (w/h).
	 */
	public void setAspectRatio(float aspectRatio) {
		if (aspectRatio == mAspectRatio) {
			return;
		}
		mAspectRatio = aspectRatio;
		requestLayout();
	}

	/**
	 * Gets the desired aspect ratio (w/h).
	 */
	public float getAspectRatio() {
		return mAspectRatio;
	}

	private void initView(Context context) {
		RelativeLayout pointContainerRl = new RelativeLayout(context);
		if (Build.VERSION.SDK_INT >= 16) {
			pointContainerRl.setBackground(mPointContainerBackgroundDrawable);
		} else {
			pointContainerRl.setBackgroundDrawable(mPointContainerBackgroundDrawable);
		}
		pointContainerRl.setPadding(mPointContainerLeftRightPadding, mPointTopBottomMargin, mPointContainerLeftRightPadding, mPointTopBottomMargin);
		LayoutParams pointContainerLp = new LayoutParams(RMP, RWC);
		// 处理圆点在顶部还是底部
		if ((mPointGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP) {
			pointContainerLp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
		} else {
			pointContainerLp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		}

		addView(pointContainerRl, pointContainerLp);
		//@TODO -----------------------------------------------------
		if (bannerButtomShade) {
			View view = LayoutInflater.from(context).inflate(R.layout.homerecycle_item_top_banner_buttom_shade, null);
			RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
					RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
			lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
			addView(view, lp);
		}


//        ViewGroup.LayoutParams vlp = new ViewGroup.LayoutParams(
//                ViewGroup.LayoutParams.WRAP_CONTENT,
//                ViewGroup.LayoutParams.WRAP_CONTENT);


		LayoutParams indicatorLp = new LayoutParams(RWC, RWC);
		indicatorLp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		if (mIsNumberIndicator) {
			mNumberIndicatorTv = new TextView(context);
			mNumberIndicatorTv.setId(R.id.banner_indicatorId);
			mNumberIndicatorTv.setGravity(Gravity.CENTER_VERTICAL);
			mNumberIndicatorTv.setSingleLine(true);
			mNumberIndicatorTv.setEllipsize(TextUtils.TruncateAt.END);
			mNumberIndicatorTv.setTextColor(mNumberIndicatorTextColor);
			mNumberIndicatorTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mNumberIndicatorTextSize);
			mNumberIndicatorTv.setVisibility(View.INVISIBLE);
			if (mNumberIndicatorBackground != null) {
				if (Build.VERSION.SDK_INT >= 16) {
					mNumberIndicatorTv.setBackground(mNumberIndicatorBackground);
				} else {
					mNumberIndicatorTv.setBackgroundDrawable(mNumberIndicatorBackground);
				}
			}
			pointContainerRl.addView(mNumberIndicatorTv, indicatorLp);
		} else {
			mPointRealContainerLl = new LinearLayout(context);
			mPointRealContainerLl.setId(R.id.banner_indicatorId);
			mPointRealContainerLl.setOrientation(LinearLayout.HORIZONTAL);
			mPointRealContainerLl.setGravity(Gravity.CENTER_VERTICAL);


			pointContainerRl.addView(mPointRealContainerLl, indicatorLp);
		}

		LayoutParams tipLp = new LayoutParams(RMP, RWC);
		tipLp.addRule(CENTER_VERTICAL);
		mTipTv = new TextView(context);
		mTipTv.setGravity(Gravity.CENTER_VERTICAL);
		mTipTv.setSingleLine(true);
		mTipTv.setEllipsize(TextUtils.TruncateAt.END);
		mTipTv.setTextColor(mTipTextColor);
		mTipTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTipTextSize);
		pointContainerRl.addView(mTipTv, tipLp);

		int horizontalGravity = mPointGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
		// 处理圆点在左边、右边还是水平居中
		if (horizontalGravity == Gravity.LEFT) {
			indicatorLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
			tipLp.addRule(RelativeLayout.RIGHT_OF, R.id.banner_indicatorId);
			mTipTv.setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
		} else if (horizontalGravity == Gravity.RIGHT) {
			indicatorLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
			tipLp.addRule(RelativeLayout.LEFT_OF, R.id.banner_indicatorId);
		} else {
			indicatorLp.addRule(RelativeLayout.CENTER_HORIZONTAL);
			tipLp.addRule(RelativeLayout.LEFT_OF, R.id.banner_indicatorId);
		}

		showPlaceholder();
	}

	public void showPlaceholder() {
		if (mPlaceholderIv == null && mPlaceholderDrawableResId != NO_PLACEHOLDER_DRAWABLE) {
			mPlaceholderIv = BGABannerUtil.getItemImageView(getContext(), mPlaceholderDrawableResId);
			mPlaceholderIv.setScaleType(mPlaceholderScaleType);
			LayoutParams layoutParams = new LayoutParams(RMP, RMP);
			layoutParams.setMargins(0, 0, 0, mContentBottomMargin);
			addView(mPlaceholderIv, layoutParams);
		}
	}

	/**
	 * 设置页码切换过程的时间长度
	 *
	 * @param duration 页码切换过程的时间长度
	 */
	public void setPageChangeDuration(int duration) {
		if (duration >= 0 && duration <= 2000) {
			mPageChangeDuration = duration;
			if (mViewPager != null) {
				mViewPager.setPageChangeDuration(duration);
			}
		}
	}

	/**
	 * 设置是否开启自动轮播，需要在 setData 方法之前调用，并且调了该方法后必须再调用一次 setData 方法
	 * 例如根据图片当图片数量大于 1 时开启自动轮播，等于 1 时不开启自动轮播
	 * mDefaultBanner.setAutoPlayAble(bannerModel.imgs.size() > 1);
	 * mDefaultBanner.setData(bannerModel.imgs, bannerModel.tips);
	 *
	 * @param autoPlayAble
	 */
	public void setAutoPlayAble(boolean autoPlayAble) {
		mAutoPlayAble = autoPlayAble;

		stopAutoPlay();

		if (mViewPager != null && mViewPager.getAdapter() != null) {
			mViewPager.getAdapter().notifyDataSetChanged();
		}
	}

	/**
	 * 设置自动轮播的时间间隔
	 *
	 * @param autoPlayInterval
	 */
	public void setAutoPlayInterval(int autoPlayInterval) {
		mAutoPlayInterval = autoPlayInterval;
	}

	/**
	 * 设置每一页的控件、数据模型和文案
	 *
	 * @param views  每一页的控件集合
	 * @param models 每一页的数据模型集合
	 * @param tips   每一页的提示文案集合
	 */
	public void setData(List<View> views, List<? extends Object> models, List<String> tips) {
		if (views == null || views.size() < 1) {
			mAutoPlayAble = false;
			views = new ArrayList<>();
			models = new ArrayList<>();
			tips = new ArrayList<>();
		}
		if (mAutoPlayAble && views.size() < 3 && mHackyViews == null) {
			mAutoPlayAble = false;
		}

		mModels = models;
		mViews = views;
		mTips = tips;

		initIndicator();
		initViewPager();
		removePlaceholder();
	}

	/**
	 * 设置布局资源id、数据模型和文案
	 *
	 * @param layoutResId item布局文件资源id
	 * @param models      每一页的数据模型集合
	 * @param tips        每一页的提示文案集合
	 */
	public void setData(@LayoutRes int layoutResId, List<? extends Object> models, List<String> tips) {
		mViews = new ArrayList<>();
		if (models == null) {
			models = new ArrayList<>();
			tips = new ArrayList<>();
		}
		for (int i = 0; i < models.size(); i++) {
			mViews.add(View.inflate(getContext(), layoutResId, null));
		}
		if (mAutoPlayAble && mViews.size() < 3) {
			mHackyViews = new ArrayList<>(mViews);
			mHackyViews.add(View.inflate(getContext(), layoutResId, null));
			if (mHackyViews.size() == 2) {
				mHackyViews.add(View.inflate(getContext(), layoutResId, null));
			}
		}
		setData(mViews, models, tips);
	}

	/**
	 * 设置数据模型和文案，布局资源默认为 ImageView
	 *
	 * @param models 每一页的数据模型集合
	 * @param tips   每一页的提示文案集合
	 */
	public void setData(List<? extends Object> models, List<String> tips) {
		setData(R.layout.bga_banner_item_image, models, tips);
	}

	/**
	 * 设置每一页的控件集合，主要针对引导页的情况
	 *
	 * @param views 每一页的控件集合
	 */
	public void setData(List<View> views) {
		setData(views, null, null);
	}

	/**
	 * 设置每一页图片的资源 id，主要针对引导页的情况
	 *
	 * @param resIds
	 */
	public void setData(@DrawableRes int... resIds) {
		List<View> views = new ArrayList<>();
		for (int resId : resIds) {
			views.add(BGABannerUtil.getItemImageView(getContext(), resId));
		}
		setData(views);
	}

	/**
	 * 设置是否允许用户手指滑动
	 *
	 * @param allowUserScrollable true表示允许跟随用户触摸滑动，false反之
	 */
	public void setAllowUserScrollable(boolean allowUserScrollable) {
		mAllowUserScrollable = allowUserScrollable;
		if (mViewPager != null) {
			mViewPager.setAllowUserScrollable(mAllowUserScrollable);
		}
	}

	/**
	 * 添加ViewPager滚动监听器
	 *
	 * @param onPageChangeListener
	 */
	public void setOnPageChangeListener(ViewPager.OnPageChangeListener onPageChangeListener) {
		mOnPageChangeListener = onPageChangeListener;
	}

	/**
	 * 设置进入按钮和跳过按钮控件资源 id，需要开发者自己处理这两个按钮的点击事件
	 *
	 * @param enterResId 进入按钮控件
	 * @param skipResId  跳过按钮控件
	 */
	public void setEnterSkipViewId(int enterResId, int skipResId) {
		if (enterResId != 0) {
			mEnterView = ((Activity) getContext()).findViewById(enterResId);
		}
		if (skipResId != 0) {
			mSkipView = ((Activity) getContext()).findViewById(skipResId);
		}
	}

	/**
	 * 设置进入按钮和跳过按钮控件资源 id 及其点击事件监听器
	 * 如果进入按钮和跳过按钮有一个不存在的话就传 0
	 * 在 BGABanner 里已经帮开发者处理了重复点击事件
	 * 在 BGABanner 里已经帮开发者处理了「跳过按钮」和「进入按钮」的显示与隐藏
	 *
	 * @param enterResId    进入按钮控件资源 id，没有的话就传 0
	 * @param skipResId     跳过按钮控件资源 id，没有的话就传 0
	 * @param guideDelegate 引导页「进入」和「跳过」按钮点击事件监听器
	 */
	public void setEnterSkipViewIdAndDelegate(int enterResId, int skipResId, GuideDelegate guideDelegate) {
		if (guideDelegate != null) {
			mGuideDelegate = guideDelegate;
			if (enterResId != 0) {
				mEnterView = ((Activity) getContext()).findViewById(enterResId);
				mEnterView.setOnClickListener(mGuideOnNoDoubleClickListener);
			}
			if (skipResId != 0) {
				mSkipView = ((Activity) getContext()).findViewById(skipResId);
				mSkipView.setOnClickListener(mGuideOnNoDoubleClickListener);
			}
		}
	}

	/**
	 * 获取当前选中界面索引
	 *
	 * @return
	 */
	public int getCurrentItem() {
		if (mViewPager == null || mViews == null) {
			return 0;
		} else {
			return mViewPager.getCurrentItem() % mViews.size();
		}
	}

	/**
	 * 获取广告页面总个数
	 *
	 * @return
	 */
	public int getItemCount() {
		return mViews == null ? 0 : mViews.size();
	}

	public List<? extends View> getViews() {
		return mViews;
	}

	public <VT extends View> VT getItemView(int position) {
		return mViews == null ? null : (VT) mViews.get(position);
	}

	public ImageView getItemImageView(int position) {
		return getItemView(position);
	}

	public List<String> getTips() {
		return mTips;
	}

	public BGAViewPager getViewPager() {
		return mViewPager;
	}

	public void setOverScrollMode(int overScrollMode) {
		mOverScrollMode = overScrollMode;
		if (mViewPager != null) {
			mViewPager.setOverScrollMode(mOverScrollMode);
		}
	}

	private void initIndicator() {
		if (mPointRealContainerLl != null) {
			mPointRealContainerLl.removeAllViews();

			if (mIsNeedShowIndicatorOnOnlyOnePage || (!mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)) {
				LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LWC, LWC);
				lp.setMargins(mPointLeftRightMargin, mPointTopBottomMargin, mPointLeftRightMargin, mPointTopBottomMargin);
				ImageView imageView;
				for (int i = 0; i < mViews.size(); i++) {
					imageView = new ImageView(getContext());
					imageView.setLayoutParams(lp);
					imageView.setImageResource(mPointDrawableResId);
					mPointRealContainerLl.addView(imageView);
				}
			}
		}
		if (mNumberIndicatorTv != null) {
			if (mIsNeedShowIndicatorOnOnlyOnePage || (!mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)) {
				mNumberIndicatorTv.setVisibility(View.VISIBLE);
			} else {
				mNumberIndicatorTv.setVisibility(View.INVISIBLE);
			}
		}
	}

	private void initViewPager() {
		if (mViewPager != null && this.equals(mViewPager.getParent())) {
			this.removeView(mViewPager);
			mViewPager = null;
		}

		mViewPager = new BGAViewPager(getContext());
		mViewPager.setOffscreenPageLimit(1);
		mViewPager.setAdapter(new PageAdapter());
		mViewPager.addOnPageChangeListener(this);
		mViewPager.setOverScrollMode(mOverScrollMode);
		mViewPager.setAllowUserScrollable(mAllowUserScrollable);
		mViewPager.setPageTransformer(true, BGAPageTransformer.getPageTransformer(mTransitionEffect));
		setPageChangeDuration(mPageChangeDuration);

		LayoutParams layoutParams = new LayoutParams(RMP, RMP);
		layoutParams.setMargins(0, 0, 0, mContentBottomMargin);
		addView(mViewPager, 0, layoutParams);

		if (mEnterView != null || mSkipView != null) {
			mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
				@Override
				public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
					if (position == getItemCount() - 2) {
						if (mEnterView != null) {
							ViewCompat.setAlpha(mEnterView, positionOffset);
						}
						if (mSkipView != null) {
							ViewCompat.setAlpha(mSkipView, 1.0f - positionOffset);
						}

						if (positionOffset > 0.5f) {
							if (mEnterView != null) {
								mEnterView.setVisibility(View.VISIBLE);
							}
							if (mSkipView != null) {
								mSkipView.setVisibility(View.GONE);
							}
						} else {
							if (mEnterView != null) {
								mEnterView.setVisibility(View.GONE);
							}
							if (mSkipView != null) {
								mSkipView.setVisibility(View.VISIBLE);
							}
						}
					} else if (position == getItemCount() - 1) {
						if (mSkipView != null) {
							mSkipView.setVisibility(View.GONE);
						}
						if (mEnterView != null) {
							mEnterView.setVisibility(View.VISIBLE);
							ViewCompat.setAlpha(mEnterView, 1.0f);
						}
					} else {
						if (mSkipView != null) {
							mSkipView.setVisibility(View.VISIBLE);
							ViewCompat.setAlpha(mSkipView, 1.0f);
						}
						if (mEnterView != null) {
							mEnterView.setVisibility(View.GONE);
						}
					}
				}
			});
		}

		if (mAutoPlayAble) {
			mViewPager.setAutoPlayDelegate(this);

			int zeroItem = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2) % mViews.size();
			mViewPager.setCurrentItem(zeroItem);

			startAutoPlay();
		} else {
			switchToPoint(0);
		}
	}

	public void removePlaceholder() {
		if (mPlaceholderIv != null && this.equals(mPlaceholderIv.getParent())) {
			removeView(mPlaceholderIv);
			mPlaceholderIv = null;
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		mMeasureSpec.width = widthMeasureSpec;
		mMeasureSpec.height = heightMeasureSpec;
		BannerAspectRatioMeasure.updateMeasureSpec(
				mMeasureSpec,
				mAspectRatio,
				getLayoutParams(),
				getPaddingLeft() + getPaddingRight(),
				getPaddingTop() + getPaddingBottom());
		super.onMeasure(mMeasureSpec.width, mMeasureSpec.height);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		if (mAutoPlayAble) {
			switch (ev.getAction()) {
				case MotionEvent.ACTION_DOWN:
					stopAutoPlay();
					break;
				case MotionEvent.ACTION_UP:
				case MotionEvent.ACTION_CANCEL:
					startAutoPlay();
					break;
			}
		}
		return super.dispatchTouchEvent(ev);
	}

	/**
	 * 设置当只有一页数据时是否显示指示器
	 *
	 * @param isNeedShowIndicatorOnOnlyOnePage
	 */
	public void setIsNeedShowIndicatorOnOnlyOnePage(boolean isNeedShowIndicatorOnOnlyOnePage) {
		mIsNeedShowIndicatorOnOnlyOnePage = isNeedShowIndicatorOnOnlyOnePage;
	}

	public void setCurrentItem(int item) {
		if (mViewPager == null || mViews == null || item > getItemCount() - 1) {
			return;
		}

		if (mAutoPlayAble) {
			int realCurrentItem = mViewPager.getCurrentItem();
			int currentItem = realCurrentItem % mViews.size();
			int offset = item - currentItem;

			// 这里要使用循环递增或递减设置，否则会ANR
			if (offset < 0) {
				for (int i = -1; i >= offset; i--) {
					mViewPager.setCurrentItem(realCurrentItem + i, false);
				}
			} else if (offset > 0) {
				for (int i = 1; i <= offset; i++) {
					mViewPager.setCurrentItem(realCurrentItem + i, false);
				}
			}

			startAutoPlay();
		} else {
			mViewPager.setCurrentItem(item, false);
		}
	}

	@Override
	protected void onVisibilityChanged(View changedView, int visibility) {
		super.onVisibilityChanged(changedView, visibility);
		if (visibility == VISIBLE) {
			startAutoPlay();
		} else if (visibility == INVISIBLE || visibility == GONE) {
			onInvisibleToUser();
		}
	}

	private void onInvisibleToUser() {
		stopAutoPlay();

		// 处理 RecyclerView 中从对用户不可见变为可见时卡顿的问题
		if (!mIsFirstInvisible && mAutoPlayAble && mViewPager != null && getItemCount() > 0) {
			switchToNextPage();
		}
		mIsFirstInvisible = false;
	}

	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		onInvisibleToUser();
	}

	@Override
	protected void onAttachedToWindow() {
		super.onAttachedToWindow();
		startAutoPlay();
	}

	public void startAutoPlay() {
		stopAutoPlay();
		if (mAutoPlayAble) {
			postDelayed(mAutoPlayTask, mAutoPlayInterval);
		}
	}

	public void stopAutoPlay() {
		if (mAutoPlayTask != null) {
			removeCallbacks(mAutoPlayTask);
		}
	}

	private void switchToPoint(int newCurrentPoint) {
		if (mTipTv != null) {
			if (mTips == null || mTips.size() < 1 || newCurrentPoint >= mTips.size()) {
				mTipTv.setVisibility(View.GONE);
			} else {
				mTipTv.setVisibility(View.VISIBLE);
				mTipTv.setText(mTips.get(newCurrentPoint));
			}
		}

		if (mPointRealContainerLl != null) {
			if (mViews != null && mViews.size() > 0 && newCurrentPoint < mViews.size() && ((mIsNeedShowIndicatorOnOnlyOnePage || (!mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)))) {
				mPointRealContainerLl.setVisibility(View.VISIBLE);
				for (int i = 0; i < mPointRealContainerLl.getChildCount(); i++) {
					mPointRealContainerLl.getChildAt(i).setEnabled(i == newCurrentPoint);
					// 处理指示器选中和未选中状态图片尺寸不相等
					mPointRealContainerLl.getChildAt(i).requestLayout();
				}
			} else {
				mPointRealContainerLl.setVisibility(View.GONE);
			}
		}

		if (mNumberIndicatorTv != null) {
			if (mViews != null && mViews.size() > 0 && newCurrentPoint < mViews.size() && ((mIsNeedShowIndicatorOnOnlyOnePage || (!mIsNeedShowIndicatorOnOnlyOnePage && mViews.size() > 1)))) {
				mNumberIndicatorTv.setVisibility(View.VISIBLE);
				mNumberIndicatorTv.setText((newCurrentPoint + 1) + "/" + mViews.size());
			} else {
				mNumberIndicatorTv.setVisibility(View.GONE);
			}
		}
	}

	/**
	 * 设置页面切换换动画
	 *
	 * @param effect
	 */
	public void setTransitionEffect(TransitionEffect effect) {
		mTransitionEffect = effect;
		if (mViewPager != null) {
			initViewPager();
			if (mHackyViews == null) {
				BGABannerUtil.resetPageTransformer(mViews);
			} else {
				BGABannerUtil.resetPageTransformer(mHackyViews);
			}
		}
	}

	/**
	 * 设置自定义页面切换动画
	 *
	 * @param transformer
	 */
	public void setPageTransformer(ViewPager.PageTransformer transformer) {
		if (transformer != null && mViewPager != null) {
			mViewPager.setPageTransformer(true, transformer);
		}
	}

	/**
	 * 切换到下一页
	 */
	private void switchToNextPage() {
		if (mViewPager != null) {
			mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
		}
	}

	@Override
	public void handleAutoPlayActionUpOrCancel(float xVelocity) {
		if (mViewPager != null) {
			if (mPageScrollPosition < mViewPager.getCurrentItem()) {
				// 往右滑
				if (xVelocity > VEL_THRESHOLD || (mPageScrollPositionOffset < 0.7f && xVelocity > -VEL_THRESHOLD)) {
					mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
				} else {
					mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
				}
			} else {
				// 往左滑
				if (xVelocity < -VEL_THRESHOLD || (mPageScrollPositionOffset > 0.3f && xVelocity < VEL_THRESHOLD)) {
					mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
				} else {
					mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
				}
			}
		}
	}

	@Override
	public void onPageSelected(int position) {
		position = position % mViews.size();
		switchToPoint(position);

		if (mOnPageChangeListener != null) {
			mOnPageChangeListener.onPageSelected(position);
		}
	}

	@Override
	public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
		mPageScrollPosition = position;
		mPageScrollPositionOffset = positionOffset;

		if (mTipTv != null) {
			if (mTips != null && mTips.size() > 0) {
				mTipTv.setVisibility(View.VISIBLE);

				int leftPosition = position % mTips.size();
				int rightPosition = (position + 1) % mTips.size();
				if (rightPosition < mTips.size() && leftPosition < mTips.size()) {
					if (positionOffset > 0.5) {
						mTipTv.setText(mTips.get(rightPosition));
						ViewCompat.setAlpha(mTipTv, positionOffset);
					} else {
						ViewCompat.setAlpha(mTipTv, 1 - positionOffset);
						mTipTv.setText(mTips.get(leftPosition));
					}
				}
			} else {
				mTipTv.setVisibility(View.GONE);
			}
		}

		if (mOnPageChangeListener != null) {
			mOnPageChangeListener.onPageScrolled(position % mViews.size(), positionOffset, positionOffsetPixels);
		}
	}

	@Override
	public void onPageScrollStateChanged(int state) {
		if (mOnPageChangeListener != null) {
			mOnPageChangeListener.onPageScrollStateChanged(state);
		}
	}

	public void setDelegate(Delegate delegate) {
		mDelegate = delegate;
	}

	public void setAdapter(Adapter adapter) {
		mAdapter = adapter;
	}

	private class PageAdapter extends PagerAdapter {

		@Override
		public int getCount() {
			return mViews == null ? 0 : (mAutoPlayAble ? Integer.MAX_VALUE : mViews.size());
		}

		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			final int finalPosition = position % mViews.size();

			View view;
			if (mHackyViews == null) {
				view = mViews.get(finalPosition);
			} else {
				view = mHackyViews.get(position % mHackyViews.size());
			}

			if (mDelegate != null) {
				view.setOnClickListener(new BGAOnNoDoubleClickListener() {
					@Override
					public void onNoDoubleClick(View view) {
						int currentPosition = mViewPager.getCurrentItem() % mViews.size();
						mDelegate.onBannerItemClick(BGABanner.this, view, mModels == null ? null : mModels.get(currentPosition), currentPosition);
					}
				});
			}

			if (mAdapter != null) {
				mAdapter.fillBannerItem(BGABanner.this, view, mModels == null ? null : mModels.get(finalPosition), finalPosition);
			}

			ViewParent viewParent = view.getParent();
			if (viewParent != null) {
				((ViewGroup) viewParent).removeView(view);
			}

			container.addView(view);
			return view;
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
		}

		@Override
		public boolean isViewFromObject(View view, Object object) {
			return view == object;
		}

		@Override
		public int getItemPosition(Object object) {
			return POSITION_NONE;
		}
	}

	private static class AutoPlayTask implements Runnable {
		private final WeakReference<BGABanner> mBanner;

		private AutoPlayTask(BGABanner banner) {
			mBanner = new WeakReference<>(banner);
		}

		@Override
		public void run() {
			BGABanner banner = mBanner.get();
			if (banner != null) {
				banner.switchToNextPage();
				banner.startAutoPlay();
			}
		}
	}

	/**
	 * item 点击事件监听器，在 BGABanner 里已经帮开发者处理了防止重复点击事件
	 *
	 * @param <V> item 视图类型，如果没有在 setData 方法里指定自定义的 item 布局资源文件的话，这里的 V 就是 ImageView
	 * @param <M> item 数据模型
	 */
	public interface Delegate<V extends View, M> {
		void onBannerItemClick(BGABanner banner, V itemView, M model, int position);
	}

	/**
	 * 适配器，在 fillBannerItem 方法中填充数据，加载网络图片等
	 *
	 * @param <V> item 视图类型，如果没有在 setData 方法里指定自定义的 item 布局资源文件的话，这里的 V 就是 ImageView
	 * @param <M> item 数据模型
	 */
	public interface Adapter<V extends View, M> {
		void fillBannerItem(BGABanner banner, V itemView, M model, int position);
	}

	/**
	 * 引导页「进入」和「跳过」按钮点击事件监听器，在 BGABanner 里已经帮开发者处理了防止重复点击事件
	 */
	public interface GuideDelegate {
		void onClickEnterOrSkip();
	}
}